import vtkmodules.all as vtk
from vtkmodules.vtkCommonCore import vtkFloatArray
from vtkmodules.web.render_window_serializer import scalarBarActorSerializer

import CloudEngine.Math.Vector3 as V3
import CloudEngine.Math.geo as geo
from CloudEngine.core.OutlineActor import OutLineActor
from CloudEngine.core.TEdge import TEdge
from CloudEngine.core.VectorActor import VectorActor
from CloudEngine.core.VScalarBarActor import VScalarBarActor
from CloudEngine.core.func.create_lut import create_lut
from CloudEngine.core.func.parse_attributes import parse_attributes
import uuid

from enum import Enum


class VTActorRenderType(Enum):
    HIDDEN = "HIDDEN"
    POINTS = "POINTS"
    WIREFRAME = "WIREFRAME"
    SURFACE = "SURFACE"
    SURFACE_WITH_EDGE = "SURFACE_WITH_EDGE"


# VTActorOptions {
#   useLookupTableScalarRange?: boolean;
#   initialScalarValue?: number[];
#   color?: number[];
#   // * 边缘数据
#   outlines?: vtkPolyData;
#   vertexes?: VertexPoint[];
#   shadow: boolean;
#   parse_attributes:bool; #️⃣ 是否要解析属性
# }


class VTActor:
    id = str(uuid.uuid4())
    # 一组的group_id 应为同一个
    gid = None
    name = ""
    type = "VT_ACTOR"
    created_by = "default"
    instance = None
    mapper = None
    origin_data = None
    # 字典 VTActorOptions
    options = dict()
    user_data = {}
    faces = []
    faceIds = []
    vertexes = []
    is_mesh = False

    outlines = None
    vertexesActor = None
    cell_normals = None
    _isShowNormals = False
    _normalsActor = None
    # 是否需要触发更新
    triggerNormalUpdate = 0

    # 属性对象
    attributes = None

    # Ⓜ️ scalar_bar 颜色条对象
    scalar_bar = None
    # 🅰️ use_scalar_bar 是否使用颜色映射表
    use_scalar_bar = False
    # Ⓜ️ 向量对象
    vector_actor = None
    # 🅰️ 默认网格颜色
    default_color = None
    # ⤵️ 解析数据的loader对象
    loader = None
    # ⤵️ 拓扑结构
    topology = None

    # 迁移完成✅
    def __init__(self, poly_data, options=dict()):

        self.options = options
        self.origin_data = poly_data
        # 清除点数据的活动标量
        poly_data.GetPointData().SetActiveScalars(None)
        # 清除单元数据的活动标量
        poly_data.GetCellData().SetActiveScalars(None)
        self.instance = vtk.vtkActor()
        self.mapper = self.init_mapper()
        self.color = options.get("color", None)
        self.default_color = options.get("default_color", [87, 96, 111, 255])
        self.instance.SetPickable(True)
        self.instance.SetMapper(self.mapper)
        self.create_cell_color()
        self.get_cell_normals()
        # 纯色渲染模式
        self.instance.GetProperty().SetLighting(False)
        # 设置边缘线颜色
        self.instance.GetProperty().SetEdgeColor(0, 0, 0)
        if self.options is not None:
            if options.get("vertexes") is not None:
                self.vertexes = options.get("vertexes")
                self.create_vertexes_ac(options.get("vertexes"))
            if options.get("shadow") is not None:
                # 设置纯色模式
                self.instance.GetProperty().SetLighting(options.get("shadow"))
            if options.get("outlines") is not None:
                self.create_outlines_ac(options.get("outlines"))
            if self.options.get("scalar_bar") is not None:
                self.create_scalar_bar(options.get("scalar_bar"))
            # if self.options.get('ColorType', None) is not None:
            #     self.apply_color_lookup_table(self.options.get('ColorType'), self.options.get('ColorLevels', 256))
            # 解析属性
            if options.get("parse_attributes") is not None:
                self.attributes = parse_attributes(poly_data)
            if options.get("IsVector", False) is not False:
                self.create_vector_field()

    def _set_use_cell_data(self):
        self.mapper.SetScalarModeToUseCellData()
        self.mapper.Modified()

    def _set_use_point_data(self):
        self.mapper.SetScalarModeToUsePointData()
        self.mapper.Modified()

    def init_mapper(self):
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(self.origin_data)
        return mapper

    def create_outlines_ac(self, edge_data: TEdge):
        outlines = OutLineActor(edge_data)
        outlines.set_render_type("SURFACE_WITH_EDGE")
        self.outlines = outlines

    def create_vertexes_ac(self, vertexes):

        points = vtk.vtkPoints()
        for item in vertexes:
            points.InsertNextPoint(item.get("XYZ"))
        poly_data = vtk.vtkPolyData()
        poly_data.SetPoints(points)

        vertex_glyph_filter = vtk.vtkVertexGlyphFilter()
        vertex_glyph_filter.SetInputData(poly_data)
        vertex_glyph_filter.Update()

        PointsActor = VTActor(poly_data)
        PointsActor.mapper.SetInputConnection(vertex_glyph_filter.GetOutputPort())
        PointsActor.instance.GetProperty().SetColor(1, 0, 0)  # 设置顶点颜色为红色
        PointsActor.instance.GetProperty().SetPointSize(10)  # 设
        PointsActor.visible_off()
        self.vertexesActor = PointsActor

    # ✅
    def set_render_type(self, render_type):
        if render_type == "HIDDEN":
            self.instance.SetVisibility(False)
            return

        representation = 0
        edgeVisibility = 0
        self.instance.SetVisibility(True)
        match render_type:
            case "POINTS":
                representation = 0
                edgeVisibility = 0
                self.vertexesActor.visible_on()
            case "WIREFRAME":
                representation = 1
                edgeVisibility = 0
            case "SURFACE":
                representation = 2
                edgeVisibility = 0
            case "SURFACE_WITH_EDGE":
                representation = 2
                edgeVisibility = 1

        if edgeVisibility == 1:
            self.instance.GetProperty().EdgeVisibilityOn()
        else:
            self.instance.GetProperty().EdgeVisibilityOff()

        match representation:
            case 2:
                self.instance.GetProperty().SetRepresentationToSurface()
            case 1:
                self.instance.GetProperty().SetRepresentationToWireframe()
            case 0:
                self.instance.GetProperty().SetRepresentationToSurface()

    # 迁移完成✅
    def set_opacity(self, v):
        self.instance.GetProperty().SetOpacity(v)

    # 迁移完成✅
    def get_opacity(self):
        return self.instance.GetProperty().GetOpacity()

    # 迁移完成✅
    def set_visible(self, vis):
        self.instance.SetVisibility(vis)

    # 迁移完成✅
    def get_visible(self):
        return self.instance.GetVisibility()

    # 迁移完成✅
    def create_cell_color(self, color=None):
        if color is None:
            color = [87, 96, 111, 255]
        input_data = self.mapper.GetInput()
        npts = input_data.GetNumberOfCells()
        colors = vtk.vtkUnsignedCharArray()
        colors.SetNumberOfComponents(4)
        colors.SetName("colors")
        for i in range(npts):
            colors.InsertNextTuple4(*color)
        self.mapper.GetInput().GetCellData().SetScalars(colors)
        self.mapper.Modified()

    def total_triangles(self):
        """
        计算并返回网格中的三角形单元总数
        """
        num_cells = self.mapper.GetInput().GetNumberOfCells()
        print("网格单元总数", num_cells)
        num_triangles = 0
        for i in range(num_cells):
            cell = self.origin_data.GetCell(i)
            if cell.GetCellType() == vtk.VTK_TRIANGLE:
                num_triangles += 1
        return num_triangles

    def get_cell_normals(self):
        # 计算法向量
        normals_filter = vtk.vtkPolyDataNormals()
        normals_filter.SetComputeCellNormals(True)
        normals_filter.SetComputePointNormals(False)
        normals_filter.SetInputData(self.origin_data)
        normals_filter.Update()
        cell_normals = normals_filter.GetOutput().GetCellData().GetNormals()
        self.cell_normals = cell_normals

    def create_normal_actor(self):
        # 计算单元中心
        cell_vertexes = self.get_cell_vertexes()
        centers = []
        for item in cell_vertexes:
            centers.append(geo.calculate_polygon_center(item))

        # 构建法向量顶点数据
        pd = vtk.vtkPolyData()
        points = vtk.vtkPoints()
        for index, v in enumerate(centers):
            points.InsertNextPoint((v.x, v.y, v.z))

        pd.SetPoints(points)
        pd.GetPointData().SetNormals(self.cell_normals)
        arrow_source = vtk.vtkArrowSource()
        glyph_mapper = vtk.vtkGlyph3DMapper()
        glyph_mapper.UseLookupTableScalarRangeOff()
        glyph_mapper.SetInputData(pd)
        glyph_mapper.SetSourceConnection(arrow_source.GetOutputPort())
        glyph_mapper.SetScaleFactor(10)
        glyph_mapper.SetOrientationModeToDirection()
        glyph_mapper.SetOrientationArray("Normals")
        glyph_mapper.SetScaleModeToScaleByMagnitude()
        glyph_mapper.SetScaleArray("Normals")
        glyph_actor = vtk.vtkActor()
        glyph_actor.SetMapper(glyph_mapper)
        glyph_actor.GetProperty().SetColor(1.0, 0.0, 0.0)
        self._normalsActor = glyph_actor

    def normals_on(self):
        if self._isShowNormals:
            return
        if self._normalsActor is None:
            self.create_normal_actor()
        self._isShowNormals = True
        self.triggerNormalUpdate = 1

    def normals_off(self):
        if not self._isShowNormals:
            return
        self._isShowNormals = False
        self.triggerNormalUpdate = 1

    def is_show_normals(self):
        return self._isShowNormals

    def get_normal_actor(self):
        return self._normalsActor

    def get_cell_vertexes(self):
        arr = []
        points = self.origin_data.GetPoints()
        polys = self.origin_data.GetPolys()

        cellSize = polys.GetNumberOfCells()
        cellArray = polys.GetData()

        cell_offset = 0

        for i in range(cellSize):
            cell_length = cellArray.GetValue(cell_offset)
            a = []
            for j in range(cell_length):
                point_id = cellArray.GetValue(cell_offset + j + 1)
                point = points.GetPoint(point_id)
                a.append(V3.Vector3(point[0], point[1], point[2]))
            arr.append(a)
            cell_offset += cell_length + 1

        return arr

    def visible_on(self):
        self.instance.SetVisibility(True)

    def visible_off(self):
        self.instance.SetVisibility(False)

    # scalars - 标量 必须是vtk对象
    def create_scalar_bar(self, scalars=None):
        IsVector = self.options.get("IsVector", False)
        self.scalar_bar = VScalarBarActor()
        self.mapper.SetScalarVisibility(True)
        v_range = scalars.GetRange()
        lut = create_lut(
            self.options.get("ColorType", ""), self.options.get("ColorLevels", 256)
        )
        if IsVector & (self.vector_actor is not None):
            # 如果向量场存在，更新其颜色映射
            self.vector_actor.set_color_mapping(lut, v_range)
        else:
            self.origin_data.GetPointData().SetScalars(scalars)
            self.mapper.SetLookupTable(lut)
            self.mapper.SetScalarRange(v_range[0], v_range[1])
            self.scalar_bar.bind_lookup_table(self.mapper.GetLookupTable())
            self.mapper.Modified()

    # 激活某个属性的显示
    def active_attribute(self, attribute: str):
        self.origin_data.GetPointData().SetActiveScalars(attribute)
        # 自动设置标量范围
        self.mapper.SetScalarRange(
            self.origin_data.GetPointData().GetScalars().GetRange()[0],
            self.origin_data.GetPointData().GetScalars().GetRange()[1],
        )
        if self.scalar_bar is None:
            self.scalar_bar = VScalarBarActor()
            self.scalar_bar.set_title(attribute)
            self.scalar_bar.bind_lookup_table(self.mapper.GetLookupTable())
        self.mapper.Modified()

    def inactive_attribute(self):
        self.origin_data.GetPointData().SetActiveScalars(None)

    def scalar_bar_on(self, scalars=None):
        if self.scalar_bar is None:
            return self.create_scalar_bar(scalars)
        else:
            self.origin_data.GetPointData().SetActiveScalars(None)
            self.origin_data.GetPointData().SetScalars(scalars)
            # 自动设置标量范围
            self.mapper.SetScalarRange(
                self.origin_data.GetPointData().GetScalars().GetRange()[0],
                self.origin_data.GetPointData().GetScalars().GetRange()[1],
            )
            self.mapper.Modified()

    # ❌ 未测试
    def scalar_bar_off(self):
        if self.scalar_bar is not None:
            self.mapper.SetScalarVisibility(False)
            self.mapper.Modified()

    def create_vector_field(self, scale=1.0):
        self.vector_actor = VectorActor(
            self.origin_data, self.cell_normals, self.options, scale
        )
        if self.vector_actor:
            self.vector_actor.set_visibility(True)

    def vector_field_on(self, vectors, scale=1.0):
        if self.vector_actor is None:
            self.create_vector_field(vectors, scale)
        self.vector_actor.set_visibility(True)

    def vector_field_off(self):
        if self.vector_actor is not None:
            self.vector_actor.set_visibility(False)

    # 设置单元格颜色
    def set_cells_color(self, ids: list, color, colors=None):
        input_data = self.mapper.GetInput()
        cell_data = input_data.GetCellData()
        scalars = cell_data.GetScalars()
        if colors is None:
            for index in range(len(ids)):
                scalars.SetTuple4(ids[index], *color)
        else:
            for index in range(len(ids)):
                scalars.SetTuple4(ids[index], *colors[index])
        cell_data.SetScalars(scalars)
        input_data.Modified()

    # 重置单元格颜色
    def reset_cell_color(self):
        mapper = self.init_mapper()
        colors = vtk.vtkUnsignedCharArray()
        colors.SetNumberOfComponents(4)
        colors.SetName("colors")
        cell_count = self.origin_data.GetNumberOfCells()
        for i in range(cell_count):
            colors.InsertTuple4(i, *self.default_color)
        mapper.GetInput().GetCellData().SetScalars(colors)
        mapper.Modified()
        self.mapper = mapper
        self.instance.SetMapper(mapper)
        self.inactive_attribute()
